package bookmark.views;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Iterator;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;

import com.google.gson.Gson;

import bookmark.constant.Constant;
import bookmark.utils.ValidationUtils;

/**
 * This sample class demonstrates how to plug-in a new workbench view. The view
 * shows data obtained from the model. The sample creates a dummy model on the
 * fly, but a real implementation would connect to the model available either in
 * this or another plug-in (e.g. the workspace). The view is connected to the
 * model using a content provider.
 * <p>
 * The view uses a label provider to define how model objects should be
 * presented in the view. Each view can present the same model objects using
 * different labels and icons, if needed. Alternatively, a single label provider
 * can be shared between views in order to ensure that objects of the same type
 * are presented in the same way everywhere.
 * <p>
 */

public class BookmarkView extends ViewPart {

	/**
	 * The ID of the view as specified by the extension.
	 */
	public static final String ID = "bookmark.views.BookmarkView";
	public static final String DATA_STORE_KEY = "bookmark_datasource";

	private TreeViewer viewer;

	private Action addFolderAction;
	private Action addBookmarkAction;
	private Action addAllBookmarkAction;
	private Action deleteAction;
	private Action renameAction;
	private Action doubleClickAction;

	class ViewContentProvider implements IStructuredContentProvider, ITreeContentProvider {

		public void inputChanged(Viewer v, Object oldInput, Object newInput) {
		}

		public void dispose() {
		}

		public Object[] getElements(Object parent) {
			return getChildren(parent);
		}

		public Object getParent(Object child) {
			if (child instanceof TreeObject) {
				return ((TreeObject) child).getParent();
			}
			return null;
		}

		public Object[] getChildren(Object parent) {
			if (parent instanceof TreeParent) {
				return ((TreeParent) parent).getChildren();
			}
			return new Object[0];
		}

		public boolean hasChildren(Object parent) {
			if (parent instanceof TreeParent)
				return ((TreeParent) parent).hasChildren();
			return false;
		}
	}

	class ViewLabelProvider extends LabelProvider {

		public String getText(Object obj) {
			return obj.toString();
		}

		public Image getImage(Object obj) {
			String imageKey = ISharedImages.IMG_OBJ_FILE;
			if (obj instanceof TreeParent)
				imageKey = ISharedImages.IMG_OBJ_FOLDER;
			return PlatformUI.getWorkbench().getSharedImages().getImage(imageKey);
			// if need to change customize image
			// return new Image(null, new FileInputStream("images/file.gif"));
		}
	}

	class NameSorter extends ViewerSorter {

		@Override
		public int compare(Viewer viewer, Object e1, Object e2) {
			TreeObject t1 = (TreeObject) e1;
			TreeObject t2 = (TreeObject) e2;
			if(t1.flag>t2.flag){
				return -1;
			}
			return super.compare(viewer, e1, e2);
		}
	}

	/**
	 * The constructor.
	 */
	public BookmarkView() {
	}

	/**
	 * This is a callback that will allow us to create the viewer and initialize
	 * it.
	 */
	private ISelection tempSelection = null;
	public void createPartControl(Composite parent) {
		viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
		viewer.setContentProvider(new ViewContentProvider());
		viewer.setLabelProvider(new ViewLabelProvider());
		viewer.setSorter(new NameSorter());

		viewer.addPostSelectionChangedListener(new ISelectionChangedListener() {


			@Override
			public void selectionChanged(SelectionChangedEvent event) {
				// TODO Auto-generated method stub
				ISelection selection = event.getSelection();
				if (selection.equals(tempSelection)) {
					viewer.setSelection(null);
				} else {
					tempSelection = selection;
				}
			}
		});

		viewer.getControl().addKeyListener(new KeyListener() {
			@Override
			public void keyReleased(KeyEvent arg0) {
			}

			@Override
			public void keyPressed(KeyEvent arg0) {
				if (arg0.keyCode == 16777227) {
					renameAction.run();
				}

			}
		});

		int ops = DND.DROP_MOVE;
		Transfer[] transfers = new Transfer[] { TextTransfer.getInstance() };
		viewer.addDragSupport(ops, transfers, new DragSourceListener() {

			@Override
			public void dragFinished(DragSourceEvent event) {
				// TODO Auto-generated method stub

			}

			@Override
			public void dragSetData(DragSourceEvent event) {
				// TODO Auto-generated method stub
				event.data = " ";
			}

			@Override
			public void dragStart(DragSourceEvent event) {
				// TODO Auto-generated method stub

			}

		});
		viewer.addDropSupport(ops, transfers, new DropTargetListener() {

			@Override
			public void dropAccept(DropTargetEvent event) {
			}

			@Override
			public void drop(DropTargetEvent event) {
				TreeItem trem = (TreeItem) event.item;
				TreeParent invisibleRoot = (TreeParent) viewer.getInput();
				ISelection selection = viewer.getSelection();

				// 增加节点
				IStructuredSelection structuredSelection = (IStructuredSelection) selection;
				for (Iterator iterator = structuredSelection.iterator(); iterator.hasNext();) {
					Object obj = iterator.next();
					TreeObject target = (TreeObject) obj;  //移动的Tree
					if (target.flag == Constant.PARENT) {
						if (trem == null) { //添加到最外面节点
							invisibleRoot.removeSelectedChild(target);
							invisibleRoot.addChild(target);
						}else{
							TreeObject targetParent = (TreeObject) trem.getData();
							if(targetParent.equals(target)){ //自己移动到自己
								return;
							}
							invisibleRoot.removeSelectedChild(target);
							invisibleRoot.addChild(targetParent, target);
						}
					}else{
						TreeObject child = new TreeObject(target.getName(), target.getProjectName());
						if (trem == null) { //添加到最外面节点
							invisibleRoot.removeSelectedChild(target);
							invisibleRoot.addChild(child);
						} else {
							TreeObject targetParent = (TreeObject) trem.getData();
							invisibleRoot.addChild(targetParent, child);
							invisibleRoot.removeSelectedChild(target);
						}
					}
				}

				// keep expand situation
				Object[] expandedElements = viewer.getExpandedElements();
				TreePath[] expandedTreePaths = viewer.getExpandedTreePaths();

				// update data source
				viewer.setInput(invisibleRoot);

				viewer.setExpandedElements(expandedElements);
				viewer.setExpandedTreePaths(expandedTreePaths);

				// save to persistent
				BookmarkView.savePersistantData(invisibleRoot);
			}

			@Override
			public void dragOver(DropTargetEvent event) {
				if (event.item == null) {
					event.detail = DND.DROP_DEFAULT;
					return;
				}
				TreeObject targetParent = (TreeObject) event.item.getData();
				if (targetParent.flag == Constant.PARENT) {
					event.detail = DND.DROP_DEFAULT;
				} else {
					event.detail = DND.DROP_NONE;
				}
			}

			@Override
			public void dragOperationChanged(DropTargetEvent event) {
			}

			@Override
			public void dragLeave(DropTargetEvent event) {
			}

			@Override
			public void dragEnter(DropTargetEvent event) {
			}
		});
		viewer.setUseHashlookup(true);

		// get data from store or else do initialization
		TreeParent invisibleRoot = this.loadPersistantData();

		// set data source
		viewer.setInput(invisibleRoot);

		// Create the help context id for the viewer's control
		PlatformUI.getWorkbench().getHelpSystem().setHelp(viewer.getControl(), "bookmark.viewer");
		makeActions();
		hookContextMenu();
		hookDoubleClickAction();
		contributeToActionBars();
	}

	private void hookContextMenu() {
		MenuManager menuMgr = new MenuManager("#PopupMenu");
		menuMgr.setRemoveAllWhenShown(true);
		menuMgr.addMenuListener(new IMenuListener() {
			public void menuAboutToShow(IMenuManager manager) {

				IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
				if (!selection.isEmpty()) {
					TreeObject target = (TreeObject) selection.getFirstElement();
					if (target instanceof TreeParent) {
						manager.add(addBookmarkAction);
						manager.add(addFolderAction);
						manager.add(deleteAction);
						manager.add(renameAction);
						// manager.add(addAllBookmarkAction);
					} else {
						manager.add(deleteAction);
						manager.add(addBookmarkAction);
						manager.add(renameAction);
					}
				} else {
					manager.add(addBookmarkAction);
					manager.add(addFolderAction);
					// manager.add(addAllBookmarkAction);
				}
			}
		});
		Menu menu = menuMgr.createContextMenu(viewer.getControl());
		viewer.getControl().setMenu(menu);
		getSite().registerContextMenu(menuMgr, viewer);
	}

	private void contributeToActionBars() {
		IActionBars bars = getViewSite().getActionBars();
		fillLocalPullDown(bars.getMenuManager());
		fillLocalToolBar(bars.getToolBarManager());
	}

	private void fillLocalPullDown(IMenuManager manager) {

	}

	private void fillLocalToolBar(IToolBarManager manager) {
		manager.add(this.addBookmarkAction);
		manager.add(this.addFolderAction);
		manager.add(this.deleteAction);
	}

	private final String treeSplit = " - ";

	@SuppressWarnings("deprecation")
	private void makeActions() {

		// remove selected folder or bookmark
		this.deleteAction = new Action() {
			public void run() {

				String title = "Confirm";
				String question = "Do you really want to delete this whole node?";
				boolean answer = MessageDialog.openConfirm(null, title, question);
				if (answer) {

					// get invisibleRoot
					TreeParent invisibleRoot = (TreeParent) viewer.getInput();

					// get selection
					ISelection selection = viewer.getSelection();

					IStructuredSelection structuredSelection = (IStructuredSelection) selection;
					for (Iterator iterator = structuredSelection.iterator(); iterator.hasNext();) {
						Object obj = iterator.next();
						// Object obj = ((IStructuredSelection)
						// selection).getFirstElement();
						if (obj == null) {
							showMessage("No selection in Bookmark View.");
						} else {
							TreeObject target = (TreeObject) obj;
							invisibleRoot.removeSelectedChild(target);
							// keep expand situation
							Object[] expandedElements = viewer.getExpandedElements();
							TreePath[] expandedTreePaths = viewer.getExpandedTreePaths();

							// update data source
							viewer.setInput(invisibleRoot);

							viewer.setExpandedElements(expandedElements);
							viewer.setExpandedTreePaths(expandedTreePaths);

							// save to persistent
							BookmarkView.savePersistantData(invisibleRoot);
						}
					}
				}

			}
		};
		this.deleteAction.setText("Delete");
		this.deleteAction.setToolTipText("Delete selected folder or bookmark.");
		this.deleteAction.setImageDescriptor(
				PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_ETOOL_DELETE));

		// use user input to add parent
		this.addFolderAction = new Action() {
			public void run() {
				String parentName;
				// create an input dialog to get user input
				String dialogTitle = "Input";
				String dialogMessage = "Please enter folder name:";
				String initialValue = "";
				InputDialog dlg = new InputDialog(null, dialogTitle, dialogMessage, initialValue,
						ValidationUtils.getIInputValidatorInstance());
				dlg.open();
				if (dlg.getReturnCode() != Window.OK) {
					return;
				} else {
					parentName = dlg.getValue();
				}

				// new a folder
				TreeParent newParent = new TreeParent(parentName);
				// get invisible root
				TreeParent invisibleRoot = (TreeParent) viewer.getInput();

				// get selection
				ISelection selection = viewer.getSelection();
				Object obj = ((IStructuredSelection) selection).getFirstElement();
				if (obj == null) {
					// no selection, default to add to the invisibleRoot
					invisibleRoot.addChild(newParent);
				} else {
					invisibleRoot.addChild((TreeObject) obj, newParent);
				}

				// keep expand situation
				Object[] expandedElements = viewer.getExpandedElements();
				TreePath[] expandedTreePaths = viewer.getExpandedTreePaths();

				// update data source
				viewer.setInput(invisibleRoot);

				viewer.setExpandedElements(expandedElements);
				viewer.setExpandedTreePaths(expandedTreePaths);

				// save to persistent
				BookmarkView.savePersistantData(invisibleRoot);
			}
		};
		this.addFolderAction.setText("Add folder ");
		this.addFolderAction.setToolTipText("Add folder ");
		this.addFolderAction.setImageDescriptor(
				PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJ_FOLDER));

		// add book mark to selected parent
		this.addBookmarkAction = new Action() {
			public void run() {
				// get active editor info
				String relativePath = "";
				String projectName = "";

				IWorkbench wb = PlatformUI.getWorkbench();
				IWorkbenchWindow window = wb.getActiveWorkbenchWindow();
				IWorkbenchPage page = window.getActivePage();
				IEditorPart editor = page.getActiveEditor();
				if (editor != null) {
					ISelection sel = editor.getEditorSite().getSelectionProvider().getSelection();
					int line = 0;
					if (sel instanceof TextSelection) {
						TextSelection ts = (TextSelection) sel;
						line = sel == null ? 0 : ts.getStartLine();
						line++;
						String text = ts == null ? "" : ts.getText();
						// String msg = String.format("Code: %s:%s ",
						// file.getFullPath(), line);
					}

					EditorPart part = (EditorPart) editor;
					IFileEditorInput input = (IFileEditorInput) editor.getEditorInput();
					IFile file = input.getFile();

					relativePath = file.getProjectRelativePath().toOSString() + ":" + line;
					projectName = file.getProject().getName();
				} else {
					// check selection from package explorer
					ISelectionService service = getSite().getWorkbenchWindow().getSelectionService();
					IStructuredSelection packageExploerSelection = (IStructuredSelection) service
							.getSelection("org.eclipse.jdt.ui.PackageExplorer");
					if (packageExploerSelection != null) {
						Object obj = packageExploerSelection.getFirstElement();
						if (obj == null) {
							showMessage("No selection in package explorer");
							return;
						} else {
							// get file info for selection from package explorer
							IResource resource = ((ICompilationUnit) obj).getResource();

							if (resource.getType() == IResource.FILE) {
								IFile ifile = (IFile) resource;
								relativePath = ifile.getProjectRelativePath().toOSString();
								projectName = ifile.getProject().getName();
							}
						}
					} else {
						showMessage("No active editor or selection in package explorer");
						return;
					}
				}

				// create leaf with file info
				TreeObject child = new TreeObject(relativePath, projectName);

				// get invisibleRoot
				TreeParent invisibleRoot = (TreeParent) viewer.getInput();

				// get selection
				ISelection selection = viewer.getSelection();
				Object obj = ((IStructuredSelection) selection).getFirstElement();
				if (obj == null) {
					// default to insert invisibleRoot
					invisibleRoot.addChild(child);
				} else {
					TreeObject targetParent = (TreeObject) obj;
					invisibleRoot.addChild(targetParent, child);
				}

				// keep expand situation
				Object[] expandedElements = viewer.getExpandedElements();
				TreePath[] expandedTreePaths = viewer.getExpandedTreePaths();

				// update data source
				viewer.setInput(invisibleRoot);

				viewer.setExpandedElements(expandedElements);
				viewer.setExpandedTreePaths(expandedTreePaths);

				// save to persistent
				BookmarkView.savePersistantData(invisibleRoot);
			}
		};
		this.addBookmarkAction.setText("Add Bookmark");
		this.addBookmarkAction.setToolTipText("Add Bookmark");
		this.addBookmarkAction.setImageDescriptor(
				PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJS_BKMRK_TSK));

		addAllBookmarkAction = new Action() {
			public void run() {
				// get active editor info
				String relativePath = "";
				String projectName = "";

				IWorkbench wb = PlatformUI.getWorkbench();
				IWorkbenchWindow window = wb.getActiveWorkbenchWindow();
				IWorkbenchPage page = window.getActivePage();
				IEditorPart[] editors = page.getEditors();
				if (editors != null) {
					for (int i = 0; i < editors.length; i++) {
						IEditorPart editor = editors[i];

						IFileEditorInput input = (IFileEditorInput) editor.getEditorInput();
						IFile file = input.getFile();
						relativePath = file.getProjectRelativePath().toOSString();
						projectName = file.getProject().getName();

						// create leaf with file info
						TreeObject child = new TreeObject(relativePath, projectName);

						// get invisibleRoot
						TreeParent invisibleRoot = (TreeParent) viewer.getInput();

						// get selection
						ISelection selection = viewer.getSelection();
						Object obj = ((IStructuredSelection) selection).getFirstElement();
						if (obj == null) {
							// default to insert invisibleRoot
							invisibleRoot.addChild(child);
						} else {
							TreeObject targetParent = (TreeObject) obj;
							invisibleRoot.addChild(targetParent, child);
						}

						// keep expand situation
						Object[] expandedElements = viewer.getExpandedElements();
						TreePath[] expandedTreePaths = viewer.getExpandedTreePaths();

						// update data source
						viewer.setInput(invisibleRoot);

						viewer.setExpandedElements(expandedElements);
						viewer.setExpandedTreePaths(expandedTreePaths);

						// save to persistent
						BookmarkView.savePersistantData(invisibleRoot);
					}
				} else {
					showMessage("No active editor");
					return;
				}

			}
		};
		this.addAllBookmarkAction.setText("Add opened files here");
		this.addAllBookmarkAction.setToolTipText("Add opened files here");
		this.addAllBookmarkAction.setImageDescriptor(
				PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJS_BKMRK_TSK));

		// rename the node
		renameAction = new Action() {
			public void run() {

				ISelection selection = viewer.getSelection();
				Object obj = ((IStructuredSelection) selection).getFirstElement();

				if (obj != null) {
					TreeObject treeObject = (TreeObject) obj;
					if (treeObject.flag == Constant.PARENT) { // 鏂囦欢澶�

						String parentName = treeObject.getName();
						// create an input dialog to get user input
						String dialogTitle = "Input";
						String dialogMessage = "Please enter folder name:";
						InputDialog dlg = new InputDialog(null, dialogTitle, dialogMessage, parentName,
								ValidationUtils.getIInputValidatorInstance());
						dlg.open();
						if (dlg.getReturnCode() != Window.OK) {
							return;
						} else {
							parentName = dlg.getValue();
						}

						treeObject.setName(parentName);
					} else { // 鏂囦欢

						String[] splitArr = treeObject.getName().split(treeSplit);

						String parentName = "", parentPath = "";
						if (splitArr.length == 2) {
							parentName = splitArr[0];
							parentPath = splitArr[1];
						} else {
							parentPath = splitArr[0];
						}

						// create an input dialog to get user input
						String dialogTitle = "Input";
						String dialogMessage = "Please enter name:";
						InputDialog dlg = new InputDialog(null, dialogTitle, dialogMessage, parentName,
								ValidationUtils.getIInputValidatorInstance());
						dlg.open();
						if (dlg.getReturnCode() != Window.OK) {
							return;
						} else {
							parentName = dlg.getValue() + treeSplit + parentPath;
						}
						treeObject.setName(parentName);
					}
				}

				TreeParent invisibleRoot = (TreeParent) viewer.getInput();
				viewer.setInput(invisibleRoot);
				BookmarkView.savePersistantData(invisibleRoot);
			}
		};

		this.renameAction.setText("Rename");
		this.renameAction.setToolTipText("Rename the folder.");

		// double click action to open file
		doubleClickAction = new Action() {
			public void run() {
				ISelection selection = viewer.getSelection();
				Object obj = ((IStructuredSelection) selection).getFirstElement();

				if (obj != null) {
					TreeObject treeObject = (TreeObject) obj;
					if (treeObject.flag == 1) {
						// expand and collapse folder when double click
						if (viewer.getExpandedState(treeObject)) {
							viewer.collapseToLevel(treeObject, 1);
						} else {
							viewer.expandToLevel(treeObject, 1);
						}
						return;
					}
					String treeName = treeObject.getName();
					String[] treeSplitArr = treeName.split(treeSplit);
					String[] split = null;

					if (treeSplitArr.length == 2) {
						split = treeName.split(treeSplit)[1].split(":");
					} else {
						split = treeName.split(treeSplit)[0].split(":");
					}

					String relativePath = split[0];

					IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
					IProject project = workspaceRoot.getProject(treeObject.getProjectName());
					IFile file1 = project.getFile((new Path(relativePath)));
					IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
					IWorkbenchPage page = window.getActivePage();
					IEditorDescriptor desc = PlatformUI.getWorkbench().getEditorRegistry()
							.getDefaultEditor(file1.getName());
					// if no right editor to find, use default text editor

					try {
						if (desc == null) {
							page.openEditor(new FileEditorInput(file1), "org.eclipse.ui.DefaultTextEditor");
						} else {

							IEditorPart openEditor = page.openEditor(new FileEditorInput(file1), desc.getId());
							int lineNumber = 0;
							if (split.length == 2) {
								lineNumber = Integer.parseInt(split[1]) - 1;
							}

							if (openEditor instanceof ITextEditor && lineNumber >= 0) {
								ITextEditor textEditor = (ITextEditor) openEditor;
								IDocumentProvider provider = textEditor.getDocumentProvider();
								provider.connect(openEditor.getEditorInput());
								IDocument document = provider.getDocument(textEditor.getEditorInput());
								IRegion line = document.getLineInformation(lineNumber);
								textEditor.selectAndReveal(line.getOffset(), line.getLength());
							}
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		};
	}

	private void hookDoubleClickAction() {
		viewer.addDoubleClickListener(new IDoubleClickListener() {
			public void doubleClick(DoubleClickEvent event) {
				tempSelection = null;
				doubleClickAction.run();
			}
		});
	}

	private void showMessage(String message) {
		MessageDialog.openInformation(viewer.getControl().getShell(), "Bookmark View", message);
	}

	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus() {
		viewer.getControl().setFocus();
	}

	/**
	 * Use eclipse Preferences API to make data persistent
	 *
	 * @param dataSource
	 */
	private static void savePersistantData(TreeParent dataSource) {
		Preferences prefs = InstanceScope.INSTANCE.getNode(ID);

		// change object to string
		Gson gson = new Gson();

		// change object byte array
		ByteArrayOutputStream b = new ByteArrayOutputStream();
		ObjectOutputStream o;
		try {
			o = new ObjectOutputStream(b);
			o.writeObject(dataSource);
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		byte[] byteDataArray = b.toByteArray();

		// use gson to change byte array to string
		String json_str = gson.toJson(byteDataArray);

		prefs.put(DATA_STORE_KEY, json_str);
		try {
			// store to disk
			prefs.flush();
		} catch (BackingStoreException e) {
			e.printStackTrace();
		}
	}

	private TreeParent loadPersistantData() {
		Preferences prefs = InstanceScope.INSTANCE.getNode(ID);

		String json_str = prefs.get(DATA_STORE_KEY, "");

		if (json_str == "") {
			// no data source yet, do initialization
			TreeParent invisibleRoot = new TreeParent("");
			return invisibleRoot;
		} else {
			Gson gson = new Gson();
			byte[] byteDataArray = gson.fromJson(json_str, byte[].class);

			// deserialize object from byteDataArray
			ByteArrayInputStream b = new ByteArrayInputStream(byteDataArray);
			ObjectInputStream o;
			TreeParent invisibleRoot = null;
			try {
				o = new ObjectInputStream(b);
				invisibleRoot = (TreeParent) o.readObject();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return invisibleRoot;
		}
	}
}